/**
 * 作者：易支烟
 * QQ：464312406
 * 博客：www.1zyan.cn
 * 更新时间：2019-6-14
 * 版本：0.1.3
 */
(function(exports) {
	//popup
	try {
		exports.bg = chrome.extension.getBackgroundPage();
	} catch (e) {}
	(()=>{
		Date.prototype.format = function(fmt)
		{
			var o = {
				"M+" : this.getMonth()+1,                 //月份
				"d+" : this.getDate(),                    //日
				"h+" : this.getHours(),                   //小时
				"m+" : this.getMinutes(),                 //分
				"s+" : this.getSeconds(),                 //秒
				"q+" : Math.floor((this.getMonth()+3)/3), //季度
				"S"  : this.getMilliseconds()             //毫秒
			};
			if(/(y+)/.test(fmt))
				fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
			for(var k in o)
				if(new RegExp("("+ k +")").test(fmt))
					fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
			return fmt;
		}
	})();
	function Base() {
		let thi = {};
		//触发事件
		function randomDouble(minNum, maxNum) {
			let num = Math.random() * (maxNum - minNum + 1);
			return Math.floor(num * 100) / 100;
		}

		function randomInt(minNum, maxNum) {
			let num = Math.random() * (maxNum - minNum + 1);
			return Math.floor(num);
		}
		thi.SetValue=function(node, text){
			if(typeof node==='string'){node=document.querySelector(node);}
			function deletePropertySafe(elem, prop) {
				let desc = Object.getOwnPropertyDescriptor(elem, prop);
				if (desc && desc.configurable) {
					delete elem[prop];
				}
			}
			function changeRangeValue(range) {
				let initMin = range.min;
				let initMax = range.max;
				let initStep = range.step;
				let initVal = Number(range.value);

				range.min = initVal;
				range.max = initVal + 1;
				range.step = 1;
				range.value = initVal + 1;
				deletePropertySafe(range, 'value');
				range.min = initMin;
				range.max = initMax;
				range.step = initStep;
				range.value = initVal;
			}
			let nodeName = node.nodeName.toLowerCase();
			let type = node.type;
			let event;
			let descriptor;
			let initialValue;
			if (nodeName === 'input' || nodeName === 'textarea') {
				descriptor = Object.getOwnPropertyDescriptor(node, 'value');
				event = document.createEvent('UIEvents');
				event.initEvent('focus', false, false);
				node.dispatchEvent(event);
				if (type === 'range') {
					changeRangeValue(node);
				} else {
					initialValue = text;
					node.value = initialValue + '#';
					deletePropertySafe(node, 'value');
				}
				node.value = initialValue;
				event = document.createEvent('HTMLEvents');
				event.initEvent('propertychange', false, false);
				event.propertyName = 'value';
				node.dispatchEvent(event);
				event = document.createEvent('HTMLEvents');
				event.initEvent('input', true, false);
				node.dispatchEvent(event);
				if (descriptor) {
					Object.defineProperty(node, 'value', descriptor);
				}
				event = document.createEvent('UIEvents');
				event.initEvent('blur', false, false);
				node.dispatchEvent(event);
			}
		};
		thi.SetValue_ = function(node, text) {
			let par=node;
			if(typeof node==='object'){
				par=thi.GetSelector(node);
			}
			thi.runJs(thi.SetValue,[par,text]);
		};

		thi.trigger = function(dom, eventName) {
			let ev = eventName;
			if (typeof eventName === "string") {
				ev = document.createEvent('HTMLEvents');
				//初始化
				let b = dom.getBoundingClientRect();
				let minX = b.x + 0.1,
					minY = b.y + 0.1,
					maxX = b.x + dom.offsetWidth,
					maxY = b.y + dom.offsetHeight;
				ev.clientX = randomDouble(minX, maxX);
				ev.clientY = randomDouble(minY, maxY);
				ev.x = randomDouble(minX, maxX);
				ev.y = randomDouble(minY, maxY);
				ev.initEvent(eventName, true, true);
			}
			if (typeof dom === "string") {
				document.querySelectorAll(dom).forEach((e) => {
					e.dispatchEvent(ev);
				})
			} else if (dom.length && dom.length > 0) {
				dom.forEach((e) => {
					e.dispatchEvent(ev);
				});
			} else {
				dom.dispatchEvent(ev);
			}
		};
		thi.getUrl = function(url) {
			return chrome.extension.getURL(url);
		};
		thi.loadClass = function(url) {
			let doc = thi.toDocument('<link rel="stylesheet" href="' + url + '">');
			(document.head || document.documentElement).appendChild(doc);
		};
		thi.loadStyle = function(css) {
			let doc = thi.toDocument('<style>' + css + '</style>');
			(document.head || document.documentElement).appendChild(doc);
		};
		thi.loadScript = function(url, callback) {
			let script = document.createElement("script");
			script.type = "text/javascript";
			if (script.readyState) {
				script.onreadystatechange = function() {
					if (script.readyState == "loaded" || script.readyState == "complete") {
						script.onreadystatechange = null;
						if (callback) callback();
					}
				};
			} else {
				script.onload = function() {
					if (callback) callback();
				};
			}
			script.src = url;
			(document.head || document.documentElement).appendChild(script);
		};
		thi.toDocument = function(html) {
			let ht = document.createElement('div');
			ht.innerHTML = html;
			return ht.firstElementChild;
		};
		thi.getScriptList = function() {
			let list = document.querySelectorAll('script');
			let linkArr = [];
			let scriptArr = [];
			list.forEach((e) => {
				if (e.src) {
					linkArr.push(e.src);
				} else if (e.innerHTML.trim()) {
					scriptArr.push(e.innerHTML.trim())
				}
			});
			return {
				linkArr,
				scriptArr
			}
		};
		//注入方式运行Js 第二个参数为参数列表
		thi.runJs = function(js,par) {
			if(typeof js==='function'){
				if(par instanceof Array){
					par=JSON.stringify(par);
					par=par.substring(1,par.length-1);
				}else if(par instanceof Object){
					par=JSON.stringify(par);
				}else if(par){
					par=`'${par.toString()}'`;
				}else{
					par='';
				}
				js=`(${js.toString()})(${par})`
			}
			//判断是否为方法
			let script = document.createElement("script");
			script.innerHTML = js;
			(document.body||document.head || document.documentElement).appendChild(script);
			thi.removeElement(script);
		};
		thi.getStr = function(length = 17) {
			let str = "abcdefghlpuv";
			str += str.toLocaleUpperCase();
			let ret = "";
			for (let i = 0; i < length; i++) {
				ret += str.charAt(Math.round(Math.random() * 23))
			}
			return ret;
		};
		thi.Ajax = {
			toPar: function(data) {
				if (typeof data === 'object') {
					let ret = null;
					let str = null;
					Object.keys(data).forEach(function(e) {
						str = encodeURIComponent((typeof data[e] === 'string' ? data[e] : JSON.stringify(data[e])));
						if (ret === null) {
							ret = e + "=" + str;
						} else {
							ret += "&" + e + "=" + str;
						}
					});
					return ret;
				} else {
					return data;
				}
			},
			get: function(url, fn, error) {
				// XMLHttpRequest对象用于在后台与服务器交换数据
				var xhr = new XMLHttpRequest();
				xhr.open('GET', url, true);
				xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				xhr.setRequestHeader("Cache-Control", "no-cache");
				xhr.onreadystatechange = function() {
					// readyState == 4说明请求已完成
					if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) {
						// 从服务器获得数据
						fn.call(this, xhr.responseText, xhr);
					} else {
						if (error) error.call(this, xhr)
					}
				};
				xhr.send();
			},
			post: function(url, data, fn, error) {
				let xhr = new XMLHttpRequest();
				xhr.open("POST", url, true);
				// 添加http头，发送信息至服务器时内容编码类型
				xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				xhr.setRequestHeader("Cache-Control", "no-cache");
				xhr.onreadystatechange = function() {
					if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
						if (fn) fn.call(this, xhr.responseText, xhr);
					} else {
						if (error) error.call(this, xhr)
					}
				};
				xhr.send(this.toPar(data));
			},
			getJSON: function(url, fn, error) {
				this.get(url, function(e) {
					fn.call(this, eval('(' + e + ')'))
				}, error)
			},
			postJSON: function(url, data, fn, error) {
				this.post(url, data, function(e) {
					fn.call(this, eval('(' + e + ')'))
				}, error)
			},
			postImg: function(file, par, url, callback, error, ) {
				let formData = new FormData();
				if (par) {
					Object.keys(par).forEach((k) => {
						formData.append(k, par[k]);
					})
				}
				if (file) {
					file.forEach((e) => {
						formData.append(e.name, e.data, e.fileName);
					});
				}
				let xmlhttp = new XMLHttpRequest();
				xmlhttp.addEventListener('load', function() {
					if (!xmlhttp.response || (xmlhttp.status !== 200 && xmlhttp.status !== 302)) {
						error && error(xmlhttp)
					} else {
						callback.call(this, xmlhttp.response);
					}
				});
				xmlhttp.open("POST", url, true);
				xmlhttp.send(formData);
			},
			getImg: function(imgUrl, callback, error) {
				let xmlhttp = new XMLHttpRequest();
				xmlhttp.responseType = 'blob';
				xmlhttp.addEventListener('load', function() {
					if (xmlhttp.status !== 200 && xmlhttp.status !== 302) {
						error && error(xmlhttp)
					} else {
						callback(xmlhttp.response);
					}
				});
				xmlhttp.open("GET", imgUrl, true);
				xmlhttp.send();
			},
			jsonp: function(url, callback) {
				//挂载方法
				let callName = "yizhiyan_" + new Date().getTime();
				//监听
				let onEval = function(e) {
					let json = e.data;
					if (json && json.type === "yizhiyan_jsonp") {
						window.removeEventListener("message", onEval);
						(document.documentElement || document.body).removeChild(xml);
						callback(json.data);
					}
				};
				window.addEventListener("message", onEval);
				thi.runJs(
					`window.${callName}=function (json) {
                    window[${callName}]=null;
                    window.postMessage({
                        type:"yizhiyan_jsonp",
                        data:json
                    },"/");
                };`
				);
				let xml = document.createElement("script");
				if (url.indexOf("?") === -1) {
					url += "?callback=" + callName;
				} else {
					url += "&callback=" + callName;
				}
				xml.src = url;
				(document.documentElement || document.body).appendChild(xml);
			}
		};
		thi.removeElement = function(dom) {
			dom.parentElement.removeChild(dom);
		};
		thi.addHandler = function(element, type, handler) {
			if (element.addEventListener) {
				element.addEventListener(type, handler, false);
			} else if (element.attachEvent) {
				element.attachEvent("on" + type, handler);
			} else {
				element["on" + type] = handler;
			}
		};
		thi.preventDefault = function(event) {
			if (event.preventDefault) {
				event.preventDefault();
			} else {
				event.returnValue = false;
			}
		};
		thi.hook_fn = function(obj, hookName, callback) {
			if (!(obj && hookName && callback)) {
				return false;
			}
			if (!thi.hooks) {
				thi.hooks = {};
			}
			if (typeof hookName === "string" && !thi.hooks[hookName]) {
				thi.hooks[hookName] = obj[hookName];
				obj[hookName] = function(a, b, c, d, e, f, g) {
					if (callback) {
						if (callback.call(this, a, b, c, d, e, f, g) === false) {
							return;
						}
					}
					thi.hooks[hookName].call(this, a, b, c, d, e, f, g);
				};
				return true;
			}
			return false;
		};
		thi.GetXPath = function(element) {
			if (element.id!==""){
				return '//*[@id=\"'+element.id+'\"]';
			}
			if (element==document.body){
				//如果是iframe
				if(window.parent!==window && window.frameElement){
					return arguments.callee(window.frameElement)+'/html/'+element.tagName;
				}else{
					return '/html/'+element.tagName;
				}
			}
			if (element.getAttribute("class")!==null){
				return arguments.callee(element.parentNode)+'/'+element.tagName+'[@class=\"'+element.getAttribute("class")+'\"]';
			}
			var ix= 0,
				siblings= element.parentNode.childNodes;

			for (var i= 0,l=siblings.length; i<l; i++) {
				var sibling= siblings[i];
				if (sibling==element){
					return arguments.callee(element.parentNode)+'/'+element.tagName+((ix+1)==1?'':'['+(ix+1)+']');
				}else if(sibling.nodeType==1 && sibling.tagName==element.tagName){
					ix++;
				}
			}
		};
		thi.GetSelect=function(element){
			let ret=element.tagName;
			if(element.className){
				element.classList.forEach((e)=>{
					ret+="."+e
				})
			}
			return ret;
		};
		thi.GetSelector = function(element) {
			if (element.id!==""){
				return '#'+element.id;
			}
			if (element==document.body){
				//如果是iframe
				if(window.parent!==window && window.frameElement){
					return arguments.callee(window.frameElement)+'>html>'+element.tagName;
				}else{
					return 'html>'+element.tagName;
				}
			}
			var ix= 0,
				siblings= element.parentNode.childNodes;

			for (var i= 0,l=siblings.length; i<l; i++) {
				var sibling= siblings[i];
				if (sibling==element){
					if (element.getAttribute("class")!==null){
						return arguments.callee(element.parentNode)+'>'+thi.GetSelect(element)+((ix+1)==1?'':':nth-of-type('+(ix+1)+')');
					}else{
						return arguments.callee(element.parentNode)+'>'+element.tagName+((ix+1)==1?'':':nth-child('+(ix+1)+')');
					}
				}else if(sibling.nodeType==1 && sibling.tagName==element.tagName){
					ix++;
				}
			}
		};
		thi.Copy = function(text) {
			if (typeof text === "string") {
				let input = document.createElement("input");
				input.value = text; // 修改文本框的内容
				document.body.appendChild(input);
				input.select(); // 选中文本
				document.execCommand("copy"); // 执行浏览器复制命令
				document.body.removeChild(input);
			} else if (typeof text == "object") {
				let input = document.createElement("input");
				input.value = text.innerText; // 修改文本框的内容
				document.body.appendChild(input);
				input.select(); // 选中文本
				document.execCommand("copy"); // 执行浏览器复制命令
				document.body.removeChild(input);
			}
		};
		//随机数
		thi.r_double = randomDouble;
		thi.r_int = randomInt;
		//菜单
		thi.MenusCreate=function (obj,onclick) {
			if(!obj.contexts){
				obj.contexts=["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"];
			}
			if(!obj.onclick){
				obj.onclick=onclick;
			}
			return chrome.contextMenus.create(obj);
		};
		return thi;
	}
	//background
	function Background() {
		let thi = Base();
		//监听消息
		thi.on = function(callback) {
			let callbackBase = callback;
			chrome.extension.onRequest.addListener(function(request, sender, callback) {
				if (callbackBase(request, sender, callback) === undefined) {
					return true;
				}
			});
		};
		//发送消息
		thi.sendTabInfo = function(tabId, sendInfo, response) {
			if (tabId) {
				thi.getTabInfo(tabId, function(tab) {
					if (tab) {
						if (tab.length && tab.length > 0) {
							for (let i = 0; i < tab.length; i++) {
								chrome.tabs.sendMessage(tab[i].id, sendInfo, response);
							}
						} else {
							chrome.tabs.sendMessage(tab.id, sendInfo, response);
						}
					}
				});
			} else {
				//给当前打开窗口发送信息
				chrome.tabs.query({
					active: true,
					currentWindow: true
				}, function(e) {
					chrome.tabs.sendMessage(e[0].id, sendInfo, response);
				})
			}
		};
		//获取tab信息
		thi.getTabInfo = function(tabId, callback) {
			try {
				if (typeof tabId === "number") {
					chrome.tabs.get(tabId, function(e) {
						if (callback) return callback.call(this, e);
					});
				} else if (typeof tabId === "string") {
					chrome.tabs.query({
						url: tabId
					}, function(e) {
						if (callback) return callback.call(this, e);
					});
				} else if (typeof tabId === "object") {
					chrome.tabs.query(tabId, function(e) {
						if (callback) return callback.call(this, e);
					});
				} else {
					//获取所有
					chrome.tabs.query({}, function(e) {
						if (callback) return callback.call(this, e);
					});
				}
			} catch (e) {
				if (callback) return callback.call(this, null);
			}
		};
		//获取tab状态 false刷新中 true加载完成
		thi.getTabStatus = function(tabId, callback) {
			thi.getTabInfo(tabId, function(e) {
				if (callback) callback.call(this, (!e) ? null : e.status === "loading" ? false : true);
			})
		};
		//创建一个tab
		thi.createTab = function(obj, callback) {
			/*
			整数	（可选） windowId
			用于创建新选项卡的窗口。默认为当前窗口。

			整数	（可选） 索引 index
			选项卡应在窗口中占据的位置。提供的值被限制在零和窗口中的选项卡数之间。

			串	（可选） 网址 url
			最初将选项卡导航到的URL。完全限定的网址必须包含一个方案（即'http://www.google.com'，而不是'www.google.com'）。相对URL相对于扩展中的当前页面。默认为新标签页。

			布尔	（可选） 有效
			选项卡是否应成为窗口中的活动选项卡。不影响窗口是否聚焦（请参阅windows.update）。默认为true。

			布尔	（可选）已 选中
			自Chrome 33以来已弃用。请使用有效。

			选项卡是否应成为窗口中的选定选项卡。默认为true

			布尔	（可选） 固定
			是否应固定标签。默认为false

			整数	（可选） openerTabId
			打开此选项卡的选项卡的ID。如果指定，则opener选项卡必须与新创建的选项卡位于同一窗口中。
			 */
			return chrome.tabs.create(obj, callback);
		};
		//修改
		thi.updateTab = function(tabId, obj, callback) {
			return chrome.tabs.update(tabId, obj, callback);
		};
		//移除tab
		thi.removeTab = function(tabId, callback) {
			return chrome.tabs.remove(tabId, callback);
		};
		//复制密码
		thi.copyTab = function(tabId, callback) {
			chrome.tabs.duplicate(tabId, callback);
		};
		//发送桌面通知
		let win = {};
		//直接向桌面发送一个文本消息
		win.sendInfo = function(icon, title, content) {
			let notification = webkitNotifications.createNotification(icon, title, content);
			notification.show();
		};
		//直接向桌面发送一个HTML消息
		win.sendHtml = function(htmlUrl) {
			let notification = webkitNotifications.createHTMLNotification(htmlUrl);
			notification.show();
		};
		//web操作模块
		let web = {};
		//监听发送之前request
		web.beforeRequest = function(callback) {
			chrome.webRequest.onBeforeRequest.addListener(callback)
		};
		//首次安装
		thi.onAppInstall = function(callback) {
			chrome.runtime.onInstalled.addListener(callback);
		};
		//浏览器启动时触发
		thi.onAppStart = function(callback) {
			chrome.runtime.onStartup.addListener(callback);
		};
		//浏览器卸载时触发
		thi.onAppUnInstall = function(callback) {
			chrome.runtime.onSuspend.addListener(callback);
		};
		//获取cookie
		thi.getCookie = function(obj, callback) {
			return chrome.cookies.getAll(obj, callback);
		};
		thi.removeCookie = function(obj, callback) {
			return chrome.cookies.remove(obj, callback);
		};
		thi.setCookie = function(obj) {
			return chrome.cookies.set(obj);
		};
		//popup页面操作模块
		let popup = {};
		popup.setTitle = function(details, callback) {
			return chrome.browserAction.setTitle(details, callback);
		};
		popup.getTitle = function(details, callback) {
			return chrome.browserAction.getTitle(details, callback);
		};
		popup.setIcon = function(details, callback) {
			return chrome.browserAction.setIcon(details, callback);
		};
		popup.setPopup = function(details, callback) {
			return chrome.browserAction.setPopup(details, callback);
		};
		popup.getPopup = function(details, callback) {
			return chrome.browserAction.getPopup(details, callback);
		};

		thi.popup = popup;
		thi.win = win;
		thi.web = web;
		this.__proto__ = thi;
	}
	//content_script
	function Content_script() {
		let thi = Base();
		//监听消息
		thi.on = function(callback) {
			let callbackBase = callback;
			chrome.runtime.onMessage.addListener(function(request, sender, callback) {
				if (callbackBase(request, sender, callback) === undefined) {
					return true;
				}
			});
		};
		//像背景页发送信息
		thi.sendBgInfo = function(info, callback) {
			try {
				return chrome.extension.sendRequest(info, callback);
			} catch (e) {
				console.error("发送信息错误："+e);
			}
		};
		//截图可视区域
		thi.picture = function(windowId, callback, isJpg) {
			let type = {
				format: "png"
			};
			if (isJpg) {
				type.format = "jpeg";
			}
			//callback 参数一：图片数据可以使用img标签显示出来
			chrome.tabs.captureVisibleTab(windowId, type, callback);
		};
		this.__proto__ = thi;
	}
	//导出
	exports.background = Background;
	exports.content_script = Content_script;
})(typeof exports === "object" && exports || this);
